package Persistencia;

import Datatypes.DataVersion;
import Datatypes.PDate;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;

public class BDMVersion{
    
    private static BDMVersion instance = null;
    private BDMConexion ct = null; 
    private PreparedStatement ps = null;
    private ResultSet rs = null;
    

    //CONSTRUCTOR
    
    private BDMVersion(){}

    //GETERS
    
    public static synchronized BDMVersion getInstance(){
        
        if(instance == null){
            
            instance = new BDMVersion();
        
        }
        
        return instance;
    
    }
    
    //SETER
    
    public void setConexion(BDMConexion BDMC){
    
        this.ct = BDMC;
    
    }

    //funciones
    /**
     * Desarrollador: Diego<br>
     * Agregamos una version pendiente.<br>
     * Agrega version pendiente recibiendo como parametro una Version<br>
     *
     * @return void
     */
    public void agregarPendiente(Pendiente v) throws Exception{
    	
        
        
        try{
    		
    		ps=this.ct.getConexion().prepareStatement("INSERT INTO versiones_pendientes(numero, fecha_v, codigo_juego, tamanio, archivo) "
    				+ "  VALUES(?,?,?,?,?)");
    		ps.setDouble(1, v.getNumero());
    		ps.setString(2,v.getFecha().getSQLDate());
    		ps.setInt(3, v.getJuego().getCodigo());
    		ps.setDouble(4, v.getTamanio());
    		ps.setString(5, v.getArchivo()); /*ARCHIVO*/
    		ps.executeUpdate();
    		    		
    	}
    	catch(SQLException e){
    		
    		throw new Exception("Error al insertar una version pendiente.<br><br>Codigo de Error: BDMVOLDJ<br>Mensaje: " + e.getMessage());
    		
    	}
        
    }
    
    public Juego buscarJuegoxCodigo(Integer ID) throws Exception{ //diego
        
        
        
        Juego j = null;
        
        try{
            
            ps = this.ct.getConexion().prepareStatement("SELECT * FROM juegos WHERE codigo = ?");
            ps.setInt(1, ID);
            ResultSet query = ps.executeQuery();
            
            while(query.next()){
                /*Juego*/
            	
            	String nombreJuego = query.getString(1);
                String desc = query.getString(2);
                Double size = query.getDouble(3);
                Integer codigo = query.getInt(4);
                Double precio = query.getDouble(5);
                String imagenJ = query.getString(6);
                
                ps = this.ct.getConexion().prepareStatement("SELECT nick_desarrollador FROM desarrolladores_de_juegos WHERE codigo_juego= ?");
                ps.setInt(1, codigo);
                ResultSet query2 = ps.executeQuery();
                
                ps = this.ct.getConexion().prepareStatement("SELECT * FROM desarrolladores WHERE nick = ?");
                ps.setString(1, query2.getString(1));
                query2 = ps.executeQuery();
                /*Desarrollador*/
                String nick = query2.getString("nick");
                String nombre = query2.getString(2);
                String apellido = query2.getString(3);
                PDate fechanac = new PDate(query2.getString(4));
                Integer edad = query2.getInt(5);
                String correo = query2.getString(6);
                String imagen = query2.getString(7);
                String weblink = query2.getString(8);
                
                Desarrollador desarrollador = new Desarrollador(nick, nombre, apellido, edad, fechanac, correo, imagen, weblink);       
                j = new Juego(desarrollador, nombreJuego, desc, size, precio, imagenJ);
                j.setCodigo(codigo);
                
               
            }
            
            
        }
        
        catch(SQLException e){
            
            throw e;
            
        }
        
        return j;
        
    }
 
    /**
     * Desarrollador: Diego<br>
     * Busca una version pendiente
     * Dado un codigo de juego, busca una version pendiente. La base de datos JAMAS debe tener mas de una version pendiente de un juego.<br>
     *
     * @return Pendiente
     */
    public Pendiente buscarPendiente(Integer juego) throws Exception{
    	
        
        
        Pendiente p = null;
    	try{
    		
            
    		ps = this.ct.getConexion().prepareStatement("SELECT * FROM  versiones_pendientes WHERE codigo_juego = ?");
    		ps.setInt(1, juego);
    		ResultSet query = ps.executeQuery();
    		while(query.next()){
    			
    			p = new Pendiente(query.getDouble(1), new PDate(query.getString(2)), null , query.getDouble(4), query.getString(5)/*Archivo*/);
    			
    		}
    		
    	}
    	catch(SQLException e){
    		
    		throw new Exception("No se pudo encontrar la version.<br><br>Codigo de Error: BDMVOLDJ<br>Mensaje: " + e.getMessage());
    	}
        
    	return p;
    }
    
    /**
     * Desarrollador: Diego<br>
     * Devuelve una lista de las versiones pendientes<br>
     * Lista de versiones pendientes con sus juegos respectivos y tal desarrollador en dicho juego<br>
     *
     * @return List<Pendiente>
     */
    public List<Pendiente> listarPendientes() throws Exception{
    	
        
        
        List<Pendiente> lista = new ArrayList();
    	
    	try{
    		
    		ps = this.ct.getConexion().prepareStatement("SELECT * FROM versiones_pendientes");
    		ResultSet query = ps.executeQuery();
    		while(query.next()){
    		        			
    			Juego j = buscarJuegoxCodigo(query.getInt("codigo_juego"));
    			
    			
    			
    			Pendiente pendiente = new Pendiente(query.getDouble("numero"), new PDate(query.getString("fecha_v")),
    										j, query.getDouble("tamanio"), query.getString("archivo")/*Archivo*/);	
    			
    			lista.add(pendiente);    			
    				
    		}
    		
    	}
    	catch(SQLException e){
    		
    		throw new Exception("No se pudo encontrar la version.<br><br>Codigo de Error: BDMVOLDJ<br>Mensaje: " + e.getMessage());
    	}        
        
    	return lista;
    }
    
    /**
     * Desarrollador: Diego<br>
     * Devuelve una lista de las versiones aprobadass<br>
     * Lista de versiones aprobadas con sus juegos respectivos y tal desarrollador en dicho juego<br>
     *
     * @return List<Aprobada>
     */
    public List<Aprobada> listarAprobadas() throws Exception{
    	
        
        
        List<Aprobada> lista = new ArrayList();
    	try{
    		
    		ps = this.ct.getConexion().prepareStatement("SELECT * FROM versiones_aprobadas");
    		ResultSet query = ps.executeQuery();
    		while(query.next()){
    			
    			Juego juego = this.buscarJuegoxCodigo(query.getInt(4));
    			Aprobada v = new Aprobada(query.getDouble(1), new PDate(query.getString(2)), 
                                                    new PDate(query.getString(3)), juego, query.getDouble(5), query.getString(6)/*Archivo*/);
    			lista.add(v);
    		}
    		
    	}
    	catch(SQLException e){
    		
    		throw new Exception("Error con el listado de versiones aprobadas.<br><br>Codigo de Error: BDMVOLDJ<br>Mensaje: " + e.getMessage());
    		
    	}
        
    	return lista;
    	
    }
    
    /**
     * Desarrollador: Diego<br>
     * Devuelve una lista de versiones (ya sea aprobadas, pendientes, o rechazadas) de 1 juego<br>
     * No le seteo el juego porque si busca por codigo de juego es medio al dope 
     *
     * @return List<Version>
     */
    public List<Version> obtenerVersionesxJuego(Integer codigoJuego) throws Exception{
    	
        
        
        List<Version> versiones = new ArrayList();
    	try{
    		
    		/*Agrego aprobadas*/
    		ps = this.ct.getConexion().prepareStatement("SELECT * FROM versiones_aprobadas WHERE codigo_juego = ?");
    		ps.setInt(1, codigoJuego);
    		ResultSet query = ps.executeQuery();
    		
    		while(query.next()){
                    
                        PDate fecha1 = new PDate(query.getString(2));
                        PDate fecha2 = new PDate(query.getString(3));
    			Aprobada v = new Aprobada(query.getDouble(1), fecha1 , fecha2, null , query.getDouble(5), query.getString(6) /*ARCHIVO*/);
    			versiones.add(v);
    		}
    		
    		/*Agrego Rechazadas*/
    		ps = this.ct.getConexion().prepareStatement("SELECT * FROM versiones_rechazadas WHERE codigo_juego = ?");
    		ps.setInt(1, codigoJuego);
    		query = ps.executeQuery();
    		
    		while(query.next()){
    			
    			Rechazada r = new Rechazada(query.getDouble(1), new PDate(query.getString(2)),
    										new PDate(query.getString(3)), query.getString(4), null, query.getDouble(6), query.getString(7) /*ARCHIVO!!*/ );
    			versiones.add(r);
    		}
    		
    		/*Agrego Pendientes*/
    		
    		ps = this.ct.getConexion().prepareStatement("SELECT * FROM versiones_pendientes WHERE codigo_juego = ?");
    		ps.setInt(1, codigoJuego);
    		query = ps.executeQuery();
    		
    		while(query.next()){
    			
    			Pendiente p = new Pendiente(query.getDouble(1), new PDate(query.getString(2)),  null , query.getDouble(4), null /*ARCHIVO*/);
    			versiones.add(p);
    			
    		}
    		
    	}
    	
    	catch(SQLException e){
    		
    		throw new Exception("Error con el listado de versiones.<br><br>Codigo de Error: BDMVOLDJ<br>Mensaje: " + e.getMessage());
    		
    	}
        
    	return versiones;
    	
    }
    
    /**
     * Desarrollador: Diego<br>
     * Determina si el juego (codigo) tiene una version pendiente.
     *  
     *
     * @return Boolean
     */
    public Boolean existePendiente(Integer codigo_juego) throws Exception{
    	
        
        
        Boolean existe = false;
    	try{
    		
    		ps = ct.getConexion().prepareStatement("SELECT * FROM versiones_pendientes WHERE codigo_juego = ?");
    		ps.setInt(1, codigo_juego);
    		ResultSet query = ps.executeQuery();
    		if(query.next()){
    			
    			existe = true;
    			
    		}
    		
    	}
    	
    	catch(SQLException e){
    		
    		throw new Exception("Error en determinar la existencia de la version pendiente.<br><br>Codigo de Error: BDMVOLDJ<br>Mensaje: " + e.getMessage());
    		
    	}
        
    	return existe;
    	
    }
    
    public Boolean tieneAprobada(Integer codJuego) throws Exception{
        
        
        
        Boolean existe = false;
        try{
            
            ps = ct.getConexion().prepareStatement("SELECT * FROM versiones_aprobadas WHERE codigo_juego = ?");
            ps.setInt(1, codJuego);
            ResultSet query = ps.executeQuery();
            if(query.next()){
                
                existe = true;
                
            }
                        
        }
        
        catch(SQLException e){
            
            throw new Exception("Error en determinar la existencia de la version pendiente.<br><br>Codigo de Error: BDMVOLDJ<br>Mensaje: " + e.getMessage());
            
        }
        
        return existe;
    }
    /**
     * Desarrollador: Diego<br>
     * Determina si el juego (codigo) y su version (numero_version) tiene una version pendiente o aprobada.
     * No pueden existir versiones aprobadas/pendientes duplicadas, osea el mismo numero de version, pero si
     * en rechazadas.	
     * @return Boolean
     */
    public Boolean existeVersion(Integer codigo_juego, Double numero_version) throws Exception{
    	
        
        
        Boolean existe = false;
    	
    	try{
    		
            ps = ct.getConexion().prepareStatement("SELECT * FROM versiones_aprobadas WHERE codigo_juego = ? AND numero = ?");
            ps.setInt(1, codigo_juego);
            ps.setDouble(2, numero_version);
            ResultSet query = ps.executeQuery();
            if(query.next()){

                    existe = true;
    			
            }    		
            if(!existe){

                ps = ct.getConexion().prepareStatement("SELECT * FROM versiones_pendientes WHERE codigo_juego = ? AND numero = ?");
                ps.setInt(1, codigo_juego);
                ps.setDouble(2, numero_version);
                query = ps.executeQuery();
                if(query.next()){

                    existe = true;
        			
                }
    			
            }
    		
    		
    	}
    	catch(SQLException e){
    		
            throw new Exception("Error en determinar la existencia de la version pendiente.<br><br>Codigo de Error: BDMVOLDJ<br>Mensaje: " + e.getMessage());
    		
    	}
        
    	return existe;
    }
    
    /**
     * Desarrollador: Diego<br>
     * Determina el maximo de la version aprobada dado un juego 
     * 	
     * @return Boolean
     */
    public Double versionMayorAprobada(Integer codigo_juego) throws Exception{
    	
        
        
    	Double numero_version = 0.0;
    	try{

            ps = ct.getConexion().prepareStatement("SELECT MAX(numero) as maximo FROM versiones_aprobadas where codigo_juego = ?;");
            ps.setInt(1, codigo_juego);
            ResultSet query = ps.executeQuery();
            
            if(query.next()){

                    numero_version = query.getDouble("maximo");
                                        
            }

    	}
    	catch(SQLException e){
    		
            throw new Exception("Error al buscar la mayor version aprobada.<br><br>Codigo de Error: BDMVOLDJ<br>Mensaje: " + e.getMessage());
    	
    	}
        
    	return numero_version;
        
    }
    
     /**
     * Desarrollador: Diego<br>
     * Quita de pendiente y agrega en rechazada.
     * 	
     * @return void
     */
    public void addRechazada(DataVersion dv, String motivo) throws Exception{
    	
        
        
    	try{
            //Quito de pendiente
            ps = ct.getConexion().prepareStatement("DELETE FROM versiones_pendientes WHERE codigo_juego = ?");
            ps.setInt(1, dv.getCodigoJuego());
            ps.executeUpdate();
            //agrego a rechazada
            ps = ct.getConexion().prepareStatement("INSERT INTO versiones_rechazadas(numero,fecha_v,fecha_r,motivo,codigo_juego,tamanio, archivo) VALUES(?,?,?,?,?,?,?)");
            ps.setDouble(1, dv.getVersion());
            ps.setString(2, dv.getFechaV().getSQLDate());
            ps.setString(3, crearFechaActual().getSQLDate());
            ps.setString(4, motivo);
            ps.setInt(5, dv.getCodigoJuego());
            ps.setDouble(6, dv.getTamanio());
            ps.setString(7, dv.getArchivo());
            ps.executeUpdate();
    		
    	}
    	
    	catch(SQLException e){
    		
    		throw new Exception("Error al rechazar la version.<br><br>Codigo de Error: BDMVOLDJ<br>Mensaje: " + e.getMessage());
    	}
        
    }
     /**
     * Desarrollador: Diego<br>
     * Quita de pendiente y agrega en aprobada
     * 	
     * @return void
     */
    public void addAprobada(DataVersion dv) throws Exception{
    	
        
        
    	try{
    		//Quito de pendiente
    		ps = ct.getConexion().prepareStatement("DELETE FROM versiones_pendientes WHERE codigo_juego = ?");
    		ps.setInt(1, dv.getCodigoJuego());
    		ps.executeUpdate();
    		//agrego a aprobada
                Double tamanio = dv.getTamanio();
    		ps = ct.getConexion().prepareStatement("INSERT INTO versiones_aprobadas(numero,fecha_v,fecha_a,codigo_juego,tamanio, archivo) VALUES(?,?,?,?,?,?)");
    		ps.setDouble(1, dv.getVersion());
    		ps.setString(2, dv.getFechaV().getSQLDate());
    		ps.setString(3, crearFechaActual().getSQLDate());
    		ps.setInt(4, dv.getCodigoJuego());
    		ps.setDouble(5, tamanio);
                ps.setString(6, dv.getArchivo());
    		ps.executeUpdate();
                //actualizo el tamanio del juego
                ps = ct.getConexion().prepareStatement("UPDATE juegos SET size = ? WHERE codigo = ?");
                ps.setDouble(1, tamanio);
                ps.setInt(2, dv.getCodigoJuego());
                
    		
    	}
    	
    	catch(SQLException e){
    		
    		throw new Exception("Error al Aprobar version.<br><br>Codigo de Error: BDMVOLDJ<br>Mensaje: " + e.getMessage());
    	
    	}
        
    }
   
    
    public PDate crearFechaActual(){
    	
    	GregorianCalendar gc = new GregorianCalendar();
        gc.setTime(new Date());            
    	
        Integer añoactual = gc.get(GregorianCalendar.YEAR);
        Integer mesactual = gc.get(GregorianCalendar.MONTH) +1;
        Integer diaActual = gc.get(GregorianCalendar.DAY_OF_MONTH);
        
        PDate fecha = new PDate(diaActual, mesactual, añoactual);
        
        
        return fecha;
    	
    }
    
       /**
     * Desarrollador: Diego<br>
     * Dado un codigo de juego, retorna la ultima version aprobada (donde el numero version sea el mas alto)
     * 	
     * @return void
     */
    public Aprobada buscarUltimaAprobada(Integer codigo_juego) throws Exception{
        
        Aprobada v = null;
        try{
            
            ps = ct.getConexion().prepareStatement("SELECT * FROM versiones_aprobadas v1 WHERE v1.codigo_juego = ? "
                    + "  AND v1.numero IN(SELECT max(numero) FROM versiones_aprobadas v2 WHERE v2.codigo_juego = ?)");
            ps.setInt(1, codigo_juego);
            ps.setInt(2, codigo_juego);
            ResultSet query = ps.executeQuery();
            
            while(query.next()){
                
                Juego j = this.buscarJuegoxCodigo(codigo_juego);
                v = new Aprobada(query.getDouble(1), new PDate(query.getString(2)), 
                                new PDate(query.getString(3)), j, query.getDouble(5), query.getString(6)/*Archivo*/);
                
                
            }
            
            
        }
        catch(SQLException e){
            
            throw new Exception("Error al obtener la ultima version del juegoo.<br><br>Codigo de Error: BDMVOLDJ<br>Mensaje: " + e.getMessage());
        
        }
        
        return v;
                
    }
    
        /**
     * Desarrollador: Diego<br>
     * 
     * Devuelve una lista de Rechazadas.<br>
     *
     * @return Pendiente
     */
    public List<Rechazada> listarRechazadas() throws Exception{

        List<Rechazada> lista = new ArrayList();
        try{
            
            ps= this.ct.getConexion().prepareStatement("SELECT * FROM versiones_rechazadas");
            ResultSet query = this.ps.executeQuery();
            while(query.next()){
    			
                Juego juego = this.buscarJuegoxCodigo(query.getInt("codigo_juego"));
                Rechazada v = new Rechazada(query.getDouble("numero"), new PDate(query.getString("fecha_v")), 
                                   new PDate(query.getString("fecha_r")), query.getString("motivo") , juego, query.getDouble("tamanio"), query.getString("archivo")/*Archivo*/);
                
                lista.add(v);
            }
            
            
        }
        catch(SQLException e){
            
            throw new Exception("Error al obtener la lista de versiones rechazadas.<br><br>Codigo de Error: BDMVOLDJ<br>Mensaje: " + e.getMessage());
            
        }
        
        return lista;
            
    }
    
         /**
     * Desarrollador: Diego<br>
     * 
     * Notifica a los clientes que la version del juego se ha actualizado.
     *
     * @return void
     */
    public void notificarClientes(Notificacion n) throws Exception{
        
        try{
            
            List<String> clientes = n.getClientes();
            Double version = n.getVersion();
            Integer codigo_juego = n.getCodigo_juego();
            Boolean notificado = n.getNotificado();
            for(String cliente : clientes){
                
                ps = ct.getConexion().prepareStatement("INSERT INTO notificaciones(nick_cliente, codigo_juego, version, notificado, link_descarga, id) "
                        + " VALUES(?,?,?,?,?,?)");
                ps.setString(1, cliente);
                ps.setInt(2, codigo_juego);
                ps.setDouble(3, version);
                ps.setBoolean(4, notificado);
                ps.setString(5, null);
                ps.setString(6, null);
                ps.executeUpdate();
                
            }
        }
        catch(SQLException e){
            
            throw new Exception("No se ha podido notificar a los clientes:  " + e.getMessage());
            
        }
       
    }
    
}
    





